package testing;

import static org.junit.Assert.*;

import hypeerweb.HyPeerWebDatabase;
import hypeerweb.Node;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HyPeerWebDatabaseTest {

	private Connection connection;

	@Before
	public void setUp() throws Exception {
		Class.forName("org.sqlite.JDBC");
		File file = new File("Databases/HyPeerWeb.sqlite");
		String absolutePath = file.getAbsolutePath();
		connection = DriverManager
				.getConnection("jdbc:sqlite:/" + absolutePath);

		Statement stat = connection.createStatement();
		stat.execute("drop table if exists Nodes;");
		stat.execute("drop table if exists Neighbors;");
		stat.execute("drop table if exists SurrogateNeighbors;");

		stat.executeUpdate("create table Nodes(WebID INTEGER PRIMARY KEY, Height INTEGER,"
				+ "Fold INTEGER, SurrogateFold INTEGER, InvSurrFold INTEGER, Child INTEGER, Parent INTEGER);");
		stat.executeUpdate("create table Neighbors(WebID INTEGER, NeighborID INTEGER, PRIMARY KEY(WebID, NeighborID));");
		stat.executeUpdate("create table SurrogateNeighbors(WebID INTEGER, NeighborID INTEGER, PRIMARY KEY(WebID, NeighborID));");
	}

	@After
	public void tearDown() throws Exception {
		connection.close();
	}

	private void setTableData1() throws SQLException {
		Statement stat = connection.createStatement();
		stat.executeUpdate("delete from Nodes;");
		stat.executeUpdate("delete from Neighbors;");
		stat.executeUpdate("delete from SurrogateNeighbors;");

		stat.execute("insert into Nodes values(0, 3, -1, 3, -1, null, null);");
		stat.execute("insert into Nodes values(1, 2, 2, -1, -1, null, null);");
		stat.execute("insert into Nodes values(2, 2, 1, -1, -1, null, null);");
		stat.execute("insert into Nodes values(3, 2, 4, -1, 0, null, null);");
		stat.execute("insert into Nodes values(4, 3, 3, -1, -1, null, null);");

		stat.execute("insert into Neighbors values(0, 1);");
		stat.execute("insert into Neighbors values(0, 2);");
		stat.execute("insert into Neighbors values(0, 4);");
		stat.execute("insert into Neighbors values(1, 0);");
		stat.execute("insert into Neighbors values(1, 3);");
		stat.execute("insert into Neighbors values(2, 0);");
		stat.execute("insert into Neighbors values(2, 3);");
		stat.execute("insert into Neighbors values(3, 1);");
		stat.execute("insert into Neighbors values(3, 2);");
		stat.execute("insert into Neighbors values(4, 0);");

		stat.execute("insert into SurrogateNeighbors values(4, 1);");
		stat.execute("insert into SurrogateNeighbors values(4, 2);");
	}

	private void verifyNode(Node current, int id, int neighborCount,
			int[] neighborIds, int fold, int surrFold, int invSurrFold) {
		assertTrue(current.getId() == id);
		List<Node> neighbors = current.getNeighbors();
		assertTrue(neighbors.size() == neighborCount);
		for (int i = 0; i < neighborCount; i++) {
			assertTrue(neighbors.get(i).getId() == neighborIds[i]);
		}
		assertTrue(current.getFold().getId() == fold);
		assertTrue(current.getSurrogateFold().getId() == surrFold);
		assertTrue(current.getInverseSurrogateFold().getId() == invSurrFold);
	}

	@Test
	public void testInitHyPeerWebDatabase() {
		try {
			setTableData1();
			HyPeerWebDatabase.initHyPeerWebDatabase();
			HyPeerWebDatabase database = HyPeerWebDatabase.getSingleton();
			Collection<Node> nodes = database.getNodes();
			assertTrue(nodes.size() == 5);

			Iterator<Node> iter = nodes.iterator();
			Node current = iter.next();
			int[] neighborIds = { 1, 2, 4 };
			verifyNode(current, 0, 3, neighborIds, -1, 3, -1);

			current = iter.next();
			neighborIds = new int[2];
			neighborIds[0] = 0;
			neighborIds[1] = 3;
			verifyNode(current, 1, 2, neighborIds, 2, -1, -1);

			current = iter.next();
			verifyNode(current, 2, 2, neighborIds, 1, -1, -1);

			current = iter.next();
			neighborIds[0] = 1;
			neighborIds[1] = 2;
			verifyNode(current, 3, 2, neighborIds, 4, -1, 0);

			current = iter.next();
			neighborIds = new int[1];
			neighborIds[0] = 0;
			verifyNode(current, 4, 1, neighborIds, 3, -1, -1);
		} catch (SQLException e) {
			e.printStackTrace();
			fail("There was an SQL error.");
		}

	}

}
